﻿using AIVision.Model;
using AIVision.Model.EntityModels;
using AIVision.Model.InspectModels;
using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace AIVision.Inspect.HCDL
{
    public class DLCheckUnitInstance : ICheckUnit
    {
        private DLInspect dLInspect;
        private string _resource_path;
        public string ResourcePath
        {
            get
            {
                return _resource_path;
            }
            set
            {
                lock (_procedure_path_lock)
                {
                    _procedure_path_initialized = false;
                }
                _resource_path = value;
            }
        }

        public List<DefectItemDto> defectItems;


        private EnumInspectType inspectType = EnumInspectType.DL;
        public EnumInspectType InspectType { get => inspectType; }

        private int okScore;
        private Lazy<HDevProgram> _Program;
        private Lazy<HDevProcedure> _GetInspectImage;
        private Lazy<HDevProcedure> _GetInspectArea;
        public void Init(string hcFilePath, List<DefectItemDto> defectItems, int okScore)
        {
            throw new Exception("初始化失败，检查类型匹配错误！");
        }

        public void Init(string hcFilePath, string processFilePath, string modelFilePath, HTuple dlDevice, List<DefectItemDto> defectItems,int okScore)
        {
            this.defectItems = defectItems;
            _resource_path = hcFilePath;
            this.okScore = okScore;
            _Program = new Lazy<HDevProgram>(() => new HDevProgram(_resource_path));
            _GetInspectImage = new Lazy<HDevProcedure>(() => new HDevProcedure(_Program.Value, "GetInspectImage"));
            _GetInspectArea = new Lazy<HDevProcedure>(() => new HDevProcedure(_Program.Value, "GetInspectArea"));
            dLInspect = new DLInspect(processFilePath, modelFilePath, dlDevice);
            dLInspect.Init();
        }

        public void Stop()
        {
            dLInspect.Stop();
            dLInspect = null;
        }
        public InspectResultModel ExUnitCheck(HObject image)
        {
            InspectResultModel result = new InspectResultModel();
            result.Defects = new Dictionary<string, HObject>();
            result.SourceImage = image;
            result.InspectImage = null;
            result.InspectType = EnumInspectType.DL.ToString();
            result.Score = 0;
            result.OKScore=okScore;
            //1、截图

            //3、按区域判断不良
            //4、合并结果


            HObject inspectImage;
            try
            {
                GetDLSpectImage(image, out inspectImage);
            }
            catch (Exception ex)
            {
                inspectImage = null;
            }
            if (inspectImage == null)
            {
                result.InspectImage = image;
                result.Defects.Add("未找到产品！", null);
                return result;
            }
            //2、深度推理
            try
            {
                dLInspect.ExInspect(inspectImage);
                result.InspectImage = dLInspect.InferenceImage;
            }
            catch (Exception ex)
            {
                result.InspectImage = inspectImage;
                result.Defects.Add("DLt推理错误！", null);
               
                return result;
            }
            //3、获取区域
            HObject inspectArea = null;
            try
            {
                GetInspectArea(dLInspect.InferenceImage, out inspectArea);
            }
            catch (Exception ex)
            {
                result.Defects.Add("区域划分错误！", null);
                return result;
            }
            HTuple areaCount = null;
            try
            {
                HOperatorSet.CountObj(inspectArea, out areaCount);
            }
            catch (Exception ex)
            {
                result.Defects.Add("区域划分错误！", null);
                return result;
            }
            int areaCountI = areaCount.I;
            if (areaCountI ==0)
            {
                result.Defects.Add("区域划分错误！", null);
                return result;
            }
            HObject selectArea = null;
            Dictionary<string, HObject> tmpDefects = new Dictionary<string, HObject>();
            for (int i = 1; i < areaCountI + 1; i++)
            {
                HOperatorSet.SelectObj(inspectArea, out selectArea, i);

                for(int j = 0;j<dLInspect.ClassNames.Length;j++)
                {
                    //获取配置的缺陷项目
                    var checkItem = defectItems.FirstOrDefault(m =>m.AreaIndex==i && m.DefectCode == dLInspect.ClassNames.SArr[j]);
                    if (checkItem == null)   //如果未配置该缺陷项目，该缺陷忽略
                        continue;
                    HObject defectRegion = new HObject();
                    HOperatorSet.Threshold(dLInspect.SegmentationImage, out defectRegion, j, j);
                    HOperatorSet.Intersection(selectArea, defectRegion, out defectRegion);
                    HOperatorSet.Connection(defectRegion, out defectRegion);
                    if (checkItem.MinArea > 0)
                        HOperatorSet.SelectShape(defectRegion, out defectRegion, "area", "and", checkItem.MinArea, 999999);
                    if (checkItem.MinHeight > 0)
                        HOperatorSet.SelectShape(defectRegion, out defectRegion, "height", "and", checkItem.MinHeight, 999999);
                    if (checkItem.MinWidth > 0)
                        HOperatorSet.SelectShape(defectRegion, out defectRegion, "width", "and", checkItem.MinWidth, 999999);
                    if (checkItem.MaxStructFactor > 0)
                        HOperatorSet.SelectShape(defectRegion, out defectRegion, "struct_factor", "and", 0, checkItem.MaxStructFactor);
                    HOperatorSet.Union1(defectRegion, out defectRegion);
                    HObject htemp;
                    HOperatorSet.GenEmptyRegion(out htemp);
                    HTuple hTuple = null;
                    HOperatorSet.TestEqualRegion(htemp, defectRegion, out hTuple);
                    if (hTuple.Length > 0 && hTuple.I == 0)
                        tmpDefects.Add(i.ToString() + ":" + checkItem.DefectName, defectRegion);
                }
            }

            if (tmpDefects.Count > 0)
            {
                //合并同类不良
                foreach(var defect in tmpDefects)
                {
                    string[] defectNames = defect.Key.Split(':');
                    if (defectNames.Length != 2)
                        continue;
                    if (!result.Defects.ContainsKey(defectNames[1]))
                        result.Defects.Add(defectNames[1], defect.Value);
                    else
                    {
                        HObject tmp = new HObject();
                        HOperatorSet.Union2(result.Defects[defectNames[1]], defect.Value, out tmp);
                        result.Defects[defectNames[1]] = tmp;
                    }
                }
                result.Score = 0;
            }
            else
                result.Score = okScore;

            return result;
        }

        public void GetDLSpectImage(HObject SourceImage, out HObject InspectImage)
        {
            //AddResourcePathToProcedurePath();
            using (HDevProcedureCall call = _GetInspectImage.Value.CreateCall())
            {
                SetParameter(call, "SourceImage", SourceImage);
                call.Execute();
                InspectImage = GetParameterHObject(call, "InspectImage");
            }
        }
        public void GetInspectArea(HObject InspectImage, out HObject InspectArea)
        {
            //AddResourcePathToProcedurePath();
            using (HDevProcedureCall call = _GetInspectArea.Value.CreateCall())
            {
                SetParameter(call, "InspectImage", InspectImage);
                call.Execute();
                InspectArea = GetParameterHObject(call, "InspectArea");
            }
        }


        private bool _procedure_path_initialized = false;
        private object _procedure_path_lock = new object();

        #region 获取、设置参数方法
        private HTuple GetParameterHTuple(HDevProcedureCall call, string name)
        {
            return call.GetOutputCtrlParamTuple(name);
        }

        private HObject GetParameterHObject(HDevProcedureCall call, string name)
        {
            return call.GetOutputIconicParamObject(name);
        }

        private HTupleVector GetParameterHTupleVector(HDevProcedureCall call, string name)
        {
            return call.GetOutputCtrlParamVector(name);
        }

        private HObjectVector GetParameterHObjectVector(HDevProcedureCall call, string name)
        {
            return call.GetOutputIconicParamVector(name);
        }

        private void SetParameter(HDevProcedureCall call, string name, HTuple tuple)
        {
            call.SetInputCtrlParamTuple(name, tuple);
        }

        private void SetParameter(HDevProcedureCall call, string name, HObject obj)
        {
            call.SetInputIconicParamObject(name, obj);
        }

        private void SetParameter(HDevProcedureCall call, string name, HTupleVector vector)
        {
            call.SetInputCtrlParamVector(name, vector);
        }

        private void SetParameter(HDevProcedureCall call, string name, HObjectVector vector)
        {
            call.SetInputIconicParamVector(name, vector);
        }
        #endregion

        private void AddResourcePathToProcedurePath()
        {
            lock (_procedure_path_lock)
            {
                if (!_procedure_path_initialized)
                {
                    new HDevEngine().AddProcedurePath(ResourcePath);
                    _procedure_path_initialized = true;
                }
            }
        }
    }
}
